<?php
class payrep01 {
  function __construct() {
  }
  
  public function report() {
    $errmess = "";
	$errcode = 0;
	$errdata = '';
	$job = array();		// Список видов работ
	
	$errs = new stdClass;
	$errs->inc = array();
	$errs->out = array();
		
	$data = new stdClass;
	$data->errcode = $errcode;
	$data->errmess = $errmess;
	$data->job = $job;
	$data->errs = $errs;
	
	$data->totinc = 0;
	$data->totout = 0;
	$data->totbal = 0;

    $sdt	= isset($_POST['sdt']) ? trim(strip_tags($_POST['sdt'])) : '';
    $fdt	= isset($_POST['fdt']) ? trim(strip_tags($_POST['fdt'])) : '';

    try
    {
// Только зарегистрированные пользователи
		if( !isset($_SESSION['user_id']) || $_SESSION['user_id'] == 0 )
			throw new Exception(ERR_M::TIMEOUT_ERROR, 999);

// sdt
		if( $sdt == '' ) $errdata .= ($errdata?'<br>':'')."Не указана дата начала периода";
		elseif( ( $sdt = Tools::check_date($sdt) ) === false )
			$errdata .= ($errdata?'<br>':'')."Дата начала периода указана неправильно.";

// fdt
		if( $fdt ) {
			if( ( $fdt = Tools::check_date($fdt) ) === false )
				$errdata .= ($errdata?'<br>':'')."Конечная дата периода указана неправильно.";
			
			if( $sdt >= $fdt ) 
				$errdata .= ($errdata?'<br>':'')."Конечная дата должна быть больше начальной.";
		}
		else {
			$fdt = date( 'Y-m-d', strtotime( $sdt ) + 86400 );
		}

		if( $errdata ) throw new Exception($errdata, 1);

// Есть ли разрешение на чтение хоть каких либо записей incoming
		$rwd = $_SESSION['priv']->incoming->rwd;
		if( ($rwd & PERM_BITS::READ_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);
		
// Есть ли разрешение на чтение хоть каких либо записей outgoing
		$rwd = $_SESSION['priv']->outgoing->rwd;
		if( ($rwd & PERM_BITS::READ_ANY) == 0 ) throw new Exception(ERR_M::DATA_OPER_DISABLED, 99);
		
// Открываем базу данных
		$db = App::me()->dbOpen();	
		
// Выполняем рассчет
		$data->sdt = $sdt;
		$data->fdt = $fdt;
		
		$this->BuildBalance( $db, $data );
		$data->sdt = Tools::str_iso2local_date( $data->sdt );
		$data->fdt = Tools::str_iso2local_date( $data->fdt );
	}
	catch (PDOException $e) {
		$errcode = 1;
		$errmess = ERR_M::DATABASE_ERROR;
	}
    catch ( Exception $e ) {
		$errcode = $e->getCode();
		$errmess = $e->getMessage();
	}

	$data->errcode = $errcode;
	$data->errmess = $errmess;
	return $data;
  }

  
  private function BuildBalance( $db, &$data ) {
  
	$sdt = $data->sdt;
	$fdt = $data->fdt;
	
// Формируем структуру баланса и платежей для каждого из видов работ
	$job = $this->BuildBalTree( $db );

// Формируем линейные массивы для считывания и суммирования платежей
	$inc = array();
	$out = array();
	foreach( $job as $jct ) {
		foreach( $jct->jtp as $jtp ) {
			foreach( $jtp->inc as $incp ) {
				$inc[ $incp->code ] = 0;
			}
			foreach( $jtp->out as $outp ) {
				$out[ $outp->code ] = 0;
			}
		}
	}
	
// Выбираем и раскидываем ВХОДЯЩИЕ платежи
// По старой схеме ВХОДЯЩИЕ это 'outgoing'
/*
	$sql =	"SELECT out_bank_date, out_amount, out_pm_type, out_account FROM outgoing ".
			"WHERE out_bank_date >= ".$db->quote($sdt)." AND out_bank_date < ".$db->quote($fdt);
	$rs = $db->query( $sql );
	while( $row = $rs->fetchObject() ) {
		if( !$row->out_pm_type || !array_key_exists( $row->out_pm_type, $inc ) ) {
			$unit = new stdClass;
			$unit->bank_date = Tools::str_iso2local_date( $row->out_bank_date );
			$unit->amount = $row->out_amount;
			$unit->account = $row->out_account;
			$unit->pm_type = $row->out_pm_type;
			$data->errs->inc[] = $unit;
		}
		else
			$inc[ $row->out_pm_type ] += $row->out_amount;
	}
	$rs->closeCursor();
*/
	$sql =	"SELECT oip_amount, oiv_pm_type, oiv_inv_num, oiv_inv_date FROM outinvpays ".
			"INNER JOIN outinvoice ON outinvoice.oiv_id = outinvpays.oip_inv_id ".
			"WHERE oip_ord_date >= ".$db->quote($sdt)." AND oip_ord_date < ".$db->quote($fdt);
	$rs = $db->query( $sql );
	while( $row = $rs->fetchObject() ) {
		if( !$row->oiv_pm_type || !array_key_exists( $row->oiv_pm_type, $inc ) ) {
			$unit = new stdClass;
			$unit->bank_date = Tools::str_iso2local_date( $row->oiv_inv_date );
			$unit->account = $row->oiv_inv_num;
			$unit->pm_type = $row->oiv_pm_type;
			$unit->amount  = $row->oip_amount;
			$data->errs->inc[] = $unit;
		}
		else
			$inc[ $row->oiv_pm_type ] += $row->oip_amount;
	}
	$rs->closeCursor();
	
// Выбираем и раскидываем ИСХОДЯЩИЕ платежи.
// По старой схеме ИСХОДЯЩИЕ єто 'incoming'
	$sql =	"SELECT inc_bank_date, inc_amount, inc_pm_type, inc_account FROM incoming ".
			"WHERE inc_bank_date >= ".$db->quote($sdt)." AND inc_bank_date < ".$db->quote($fdt);
	$rs = $db->query( $sql );
	while( $row = $rs->fetchObject() ) {
		if( !$row->inc_pm_type || !array_key_exists( $row->inc_pm_type, $out ) ) {
			$unit = new stdClass;
			$unit->bank_date = Tools::str_iso2local_date( $row->inc_bank_date );
			$unit->amount = $row->inc_amount;
			$unit->account = $row->inc_account;
			$unit->pm_type = $row->inc_pm_type;
			$data->errs->out[] = $unit;
		}
		else
			$out[ $row->inc_pm_type ] += $row->inc_amount;
	}
	$rs->closeCursor();
	
// Переносим плтежи из линейных массивов в структуры
	foreach( $job as $jct ) {						// Категории
		foreach( $jct->jtp as $jtp ) {				// Виды работ
			foreach( $jtp->inc as $incp ) {			// Входящие
				$incp->sum = $inc[ $incp->code ];	
			}
			foreach( $jtp->out as $outp ) {			// Исходящие
				$outp->sum = $out[ $outp->code ];
			}
		}
	}
	unset( $inc );
	unset( $out );
	
// Формируем баланс по группам платежей
	$data->totinc = 0;
	$data->totout = 0;
	$data->totbal = 0;

	foreach( $job as &$jct ) {
		foreach( $jct->jtp as &$jtp ) {
			foreach( $jtp->bal as &$bal ) {
			
				// Исходящие - затраты
				$sum = 0;
				foreach( $jtp->out as $outp ) {
					if( $bal->id == $outp->btp_id )
						$sum += $outp->sum;
				}
				$bal->sum -= $sum;		// Зачисляем на i-тый баланс с минусом ( не накопление )
				$jtp->otot += $sum;		// Накопление по всем расходам
				
				// Входящие - доходы
				$sum = 0;
				foreach( $jtp->inc as $incp ) {
					if( $bal->id == $incp->btp_id )
						$sum += $incp->sum;
				}
				$bal->sum += $sum;		// Зачисляем на i-тый баланс с плюсом
				$jtp->itot += $sum;		// Накопление по всем расходам
			}
			
			$jtp->itot = round( $jtp->itot );
			$jtp->otot = round( $jtp->otot );
			$jtp->btot = $jtp->itot - $jtp->otot;
			
			$jct->incpays += $jtp->itot;
			$jct->outpays += $jtp->otot;			
		}
		$jct->balance = $jct->incpays - $jct->outpays;
		
		$data->totinc += $jct->incpays;
		$data->totout += $jct->outpays;
	}
	$data->totbal = $data->totinc - $data->totout;

	$data->job = $job;
  }

  
// 
// Для каждой из работ формирует пустую структуру баланса и платежей,
// соответствующую типу работы.
//
  private function BuildBalTree( $db ) {
	
// Формируем массив категорий работ
	$job = array();
			
	$rs = $db->query( "SELECT * FROM jobcats ORDER BY jct_order" );
    while( $row = $rs->fetchObject() ) {
		$unit = new stdClass;
		$unit->id = $row->jct_id;
		$unit->name = $row->jct_name;
		$unit->jtp = array();
		$unit->incpays = 0;
		$unit->outpays = 0;
		$unit->balance = 0;
		$job[] = $unit;
	}
	$rs->closeCursor();
	
	foreach( $job as &$jtc ) {
		$rs = $db->query( "SELECT * FROM jobtypes WHERE jtp_cat_id = ".$jtc->id." ORDER BY jtp_code" );
		while( $row = $rs->fetchObject() ) {
			$unit = new stdClass;
			$unit->id = $row->jtp_id;
			$unit->name = $row->jtp_descr;
			$unit->itot = 0;
			$unit->otot = 0;
			$unit->btot = 0;
			$unit->bal = array();
			$unit->out = array();
			$unit->inc = array();
			$jtc->jtp[] = $unit;
		}
		$rs->closeCursor();
		
// Для каждого типа работы считываем список балансов
		foreach( $jtc->jtp as &$jtp ) {		
			$rs = $db->query( 
				"SELECT btp_id, btp_code FROM baltypes ".
				"WHERE btp_jtp_id = ".$jtp->id." ORDER BY btp_ord"
			);
			while( $row = $rs->fetchObject() ) {
				$unit = new stdClass;
				$unit->id = $row->btp_id;
				$unit->code = $row->btp_code;
				$unit->sum = 0;
				$jtp->bal[] = $unit;
			}
			$rs->closeCursor();
	
// Исходящие
			$rs = $db->query( 
				"SELECT otp_id, otp_code, otp_btp_id FROM outtypes ".
				"WHERE otp_jtp_id = ".$jtp->id." ORDER BY otp_ord"
			);
			while( $row = $rs->fetchObject() ) {
				$unit = new stdClass;
				$unit->id = $row->otp_id;
				$unit->code = $row->otp_code;
				$unit->btp_id = $row->otp_btp_id;
				$unit->sum = 0;
				$jtp->out[] = $unit;
			}
			$rs->closeCursor();
		
// Входящие		
			$rs = $db->query( 
				"SELECT itp_id, itp_code, itp_btp_id FROM inctypes ".
				"WHERE itp_jtp_id = ".$jtp->id." ORDER BY itp_ord"
			);
			while( $row = $rs->fetchObject() ) {
				$unit = new stdClass;
				$unit->id = $row->itp_id;
				$unit->code = $row->itp_code;
				$unit->btp_id = $row->itp_btp_id;
				$unit->sum = 0;
				$jtp->inc[] = $unit;
			}
			$rs->closeCursor();
		}
	}
	
	return $job;
  }

} // End of payrep01 class
?>